package org.daochong.lang;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class Message {
	public static final Map<String, Locale> locales;
	private static Message MESSAGES;
	public static final String DEFAULT_PATH = "/messages";

	static {
		locales = new LinkedHashMap<String, Locale>();
		try {
			Class<Locale> cls = Locale.class;
			for (Field field : cls.getDeclaredFields()) {
				if (!field.getName().startsWith("default") && !field.getName().equals("ROOT")
						&& field.getType().getName().equals("java.util.Locale")
						&& Modifier.isStatic(field.getModifiers())) {
					field.setAccessible(true);
					Locale locale = (Locale) field.get(null);
					if (locale != null) {
						locales.put(locale.toString(), locale);
					}
					field.setAccessible(false);
				}
			}
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	// 验证类错误 10XX；
	// 空指针
	public static final int CODE_NULL = 1001;
	// 空值
	public static final int CODE_EMPTY = 1002;

	// 长度大于
	public static final int CODE_LENGTH_MAX = 1003;
	// 长度小于
	public static final int CODE_LENGTH_MIN = 1004;
	// 长度区间
	public static final int CODE_LENGTH_REGION = 1005;

	// 数字大于
	public static final int CODE_NUMBER_MAX = 1006;
	// 数字小于
	public static final int CODE_NUMBER_MIN = 1007;
	// 数字区间
	public static final int CODE_NUMBER_REGION = 1008;

	// 日期大于
	public static final int CODE_DATE_MAX = 1009;
	// 日期小于
	public static final int CODE_DATE_MIN = 1010;
	// 日期区间
	public static final int CODE_DATE_REGION = 1011;
	public static final int CODE_SERVLET_EXCEPTION = 1097;
	public static final int CODE_IO_EXCEPTION = 1098;
	public static final int CODE_UNKOWN_EXCEPTION = 1099;

	// 必须是XX错误 11XX
	// {0} 必须是XX
	public static final int CODE_IS_NOT_CLASS = 1100;
	public static final int CODE_IS_NOT_MAIL = 1101;
	public static final int CODE_IS_NOT_NUMBER = 1102;
	public static final int CODE_IS_NOT_INT = 1103;
	public static final int CODE_IS_NOT_DOUBLE = 1104;
	public static final int CODE_IS_NOT_DATE = 1105;
	public static final int CODE_IS_NOT_IDCARD = 1106;
	public static final int CODE_IS_NOT_CREDIT = 1107;
	public static final int CODE_IS_NOT_BANKCARD = 1108;
	public static final int CODE_IS_NOT_WEB_URL = 1109;
	// 不符合规范
	public static final int CODE_NOT_VALIDATA = 1010;

	public static final int CODE_IS_NOT_IP = 1111;
	public static final int CODE_IS_NOT_IPV6 = 1107;
	public static final int CODE_IS_NOT_MAC_ADDRESS = 1112;
	public static final int CODE_IS_NOT_MOBILE = 1113;
	public static final int CODE_IS_NOT_PC = 1114;
	public static final int CODE_IS_NOT_CLIENT = 1115;

	// Entity 错误12XX
	// Bean 存在
	public static final int CODE_ENTITY_EXISTS = 1201;
	// Bean 不存在
	public static final int CODE_ENTITY_NOT_EXISTS = 1202;

	// 数据库及SQL错误13XX
	public static final int CODE_SQL_EXCEPTION = 1300;

	public static final int CODE_DB_CONNECITON_FAILE = 1301;
	// Bean 不存在
	public static final int CODE_DB_CONNECITON_ERROR = 1302;

	private Map<String, Map<String, String>> messages;
	private Object[] nullValue = new Object[0];

	public Message() {
		messages = new HashMap<String, Map<String, String>>();
	}

	public String getMessage(int code) {
		return getMessage(String.valueOf(code), LocaleContext.getLocale(), nullValue);
	}

	public String getMessage(int code, Object... params) {
		return getMessage(String.valueOf(code), LocaleContext.getLocale(), params);
	}

	public String getMessage(int code, Locale locale) {
		return getMessage(String.valueOf(code), locale, nullValue);
	}

	public String getMessage(int code, Locale locale, Object... params) {
		return getMessage(String.valueOf(code), locale, params);
	}

	public String getMessage(String code) {
		return getMessage(code, LocaleContext.getLocale(), nullValue);
	}

	public String getMessage(String code, Object... params) {
		return getMessage(code, LocaleContext.getLocale(), params);
	}

	public String getMessage(String code, Locale locale) {
		return getMessage(code, locale, nullValue);
	}

	public String getMessage(String code, Locale locale, Object... params) {
		String str = locale.toString();
		Map<String, String> map = messages.get(str);
		if (map != null) {
			String re = map.get(code);
			if (re != null) {
				if (params != null && params.length > 0) {
					for (int i = 0; i < params.length; i++) {
						if (params[i] != null) {
							re = re.replaceAll("\\{" + i + "\\}", params[i].toString());
						} else {
							re = re.replaceAll("\\{" + i + "\\}", "");
						}
					}
					return re;
				} else {
					return re;
				}
			}
		}
		return "";
	}

	public void addMessage(String code, String message) {
		addMessage(code, message, LocaleContext.getLocale());
	}

	public void addMessage(String code, String message, Locale locale) {
		String str = locale.toString();
		Map<String, String> map = messages.get(str);
		if (map == null) {
			map = new HashMap<String, String>();
			messages.put(str, map);
		}
		map.put(code, message);
	}

	public void load(String classPath) {
		load(LocaleContext.getLocale(), classPath);
	}

	public void load(Locale locale, String classPath) {
		load(LocaleContext.getLocale(), Message.class.getResourceAsStream(classPath));
	}

	public void load(String... classPaths) {
		for (String str : classPaths) {
			load(str);
		}
	}

	public void load(Locale locale, String... classPaths) {
		for (String str : classPaths) {
			load(locale, str);
		}
	}

	public void load(File file) {
		load(LocaleContext.getLocale(), file);
	}

	public void load(Locale locale, File file) {
		try {
			load(locale, new FileInputStream(file));
		} catch (FileNotFoundException e) {
		}
	}

	public void load(File... files) {
		for (File file : files) {
			load(file);
		}
	}

	public void load(Locale locale, File... files) {
		for (File file : files) {
			load(locale, file);
		}
	}

	public void load(Locale locale, InputStream in) {
		Properties p = new Properties();
		p.load(in);
		for (String key : p.keys()) {
			try {
				addMessage(key, p.getProperty(key), locale);
			} catch (Throwable e) {

			}
		}

	}

	public static void init() {
		MESSAGES = new Message();
		List<Resource> rs = Resource.getResources(DEFAULT_PATH+"/**/*.properties");
		loadResources(rs);
	}

	public static void loadResources(List<Resource> rs) {
		if (rs != null) {
			Collections.sort(rs, new Comparator<Resource>() {

				public int compare(Resource source, Resource target) {
					if (!source.isJar()) {
						return 1;
					}
					if (!target.isJar()) {
						return -1;
					}
					return 0;
				}

			});
			List<String> list = new ArrayList<String>();
			for (Resource r : rs) {
				String fn = r.getFileName();
				if (!fn.endsWith(".properties"))
					continue;
				
				String loc = null;
				if (r.isJar()) {
					String source = r.getSource();
					source = source.substring(source.lastIndexOf('!') + 1, source.length() - fn.length());
					if (source.length() == 0)
						continue;
					source = source.substring(0, source.length() - 1);
					int pos = source.lastIndexOf("/");
					loc = source;
					if (pos > 0) {
						loc = source.substring(pos + 1);
					}
				} else {
					loc = r.getSourceFile().getParentFile().getName();
				}
				if (list.contains(loc + ":" + fn) || !locales.containsKey(loc))
					continue;
				try {
					SystemLogger.info("Load", r.getSource());
					MESSAGES.load(locales.get(loc), r.getInputStream());
				} catch (IOException e) {
					e.printStackTrace();
				}
				list.add(loc + ":" + fn);
			}
		}
	}

	public static Message getInstance() {
		if (MESSAGES == null) {
			init();
		}
		return MESSAGES;
	}

	public static void loadFile(Locale locale, File file) {
		MESSAGES.load(locale, file);
	}

	public static void loadFile(Locale locale, File... files) {
		MESSAGES.load(locale, files);
	}

	public static void loadFile(Locale locale, String classPath) {
		MESSAGES.load(locale, classPath);
	}

	public static void loadFile(Locale locale, String... classPaths) {
		MESSAGES.load(locale, classPaths);
	}

	public static void loadFolder(String folder) {
		System.out.println("Load Message:" + folder);
		File f = new File(folder);
		if (f.exists() && f.isDirectory()) {
			loadFolder(f);
		}
	}

	public static void loadFolder(File folder) {
		for (File file : folder.listFiles()) {
			if (file.isDirectory() && locales.containsKey(file.getName())) {
				for (File f : file.listFiles()) {
					if (f.getName().endsWith(".properties")) {
						System.out.println(f);
						loadFile(locales.get(file.getName()), f);
					}
				}
			}
		}
	}

	public static void main(String[] args) {
		String source = "a.jar!messages/zh_CN/a.properties";
		String fn = "a.properties";
		source = source.substring(source.lastIndexOf('!') + 1, source.length() - fn.length());
		System.out.println(source.length());

	}
}
